#include "instructions/conversions/conversions.h"

namespace jvm {
namespace instructions {

// Float conversions
void F2D::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    float f = stack->popFloat();
    double d = static_cast<double>(f);
    stack->pushDouble(d);
}

void F2I::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    float f = stack->popFloat();
    int32_t i = static_cast<int32_t>(f);
    stack->pushInt(i);
}

void F2L::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    float f = stack->popFloat();
    int64_t l = static_cast<int64_t>(f);
    stack->pushLong(l);
}

// Integer conversions
void I2B::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    int32_t i = stack->popInt();
    int32_t b = static_cast<int32_t>(static_cast<int8_t>(i));
    stack->pushInt(b);
}

void I2C::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    int32_t i = stack->popInt();
    int32_t c = static_cast<int32_t>(static_cast<uint16_t>(i));
    stack->pushInt(c);
}

void I2S::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    int32_t i = stack->popInt();
    int32_t s = static_cast<int32_t>(static_cast<int16_t>(i));
    stack->pushInt(s);
}

void I2L::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    int32_t i = stack->popInt();
    int64_t l = static_cast<int64_t>(i);
    stack->pushLong(l);
}

void I2F::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    int32_t i = stack->popInt();
    float f = static_cast<float>(i);
    stack->pushFloat(f);
}

void I2D::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    int32_t i = stack->popInt();
    double d = static_cast<double>(i);
    stack->pushDouble(d);
}

// Long conversions
void L2D::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    int64_t l = stack->popLong();
    double d = static_cast<double>(l);
    stack->pushDouble(d);
}

void L2F::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    int64_t l = stack->popLong();
    float f = static_cast<float>(l);
    stack->pushFloat(f);
}

void L2I::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    int64_t l = stack->popLong();
    int32_t i = static_cast<int32_t>(l);
    stack->pushInt(i);
}

// Double conversions
void D2F::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    double d = stack->popDouble();
    float f = static_cast<float>(d);
    stack->pushFloat(f);
}

void D2I::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    double d = stack->popDouble();
    int32_t i = static_cast<int32_t>(d);
    stack->pushInt(i);
}

void D2L::execute(std::shared_ptr<rtda::Frame> frame) {
    auto stack = frame->getOperandStack();
    double d = stack->popDouble();
    int64_t l = static_cast<int64_t>(d);
    stack->pushLong(l);
}

} // namespace instructions
} // namespace jvm